﻿
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

FILE * toU_File = NULL;
FILE * frU_File = NULL;
FILE * c_File = NULL;

static char * pbCharsetName;
static unsigned short toTab[65536];
static unsigned short frTab[65536];
static unsigned char linedata[4096];
static void showhelp();
static void MapToC();
static void BuildAnsi2UniTable();
static void BuildUni2AnsiTable();

int main(int argc, char** argv)
{
    if ( argc < 5 )
    {
        showhelp();
        return 0;
    }
    pbCharsetName = argv[1];
    toU_File = fopen(argv[2], "rt");
    frU_File = fopen(argv[3], "rt");
    c_File = fopen(argv[4], "wt");
    if ( toU_File==NULL ) {
        printf("cannot load file : %s\n", argv[2]);
        if ( toU_File ) fclose(toU_File);
        if ( frU_File ) fclose(frU_File);
        if ( c_File ) fclose(c_File);
        return 1;
    }
    if ( frU_File==NULL ) {
        printf("cannot load file : %s\n", argv[3]);
        if ( toU_File ) fclose(toU_File);
        if ( frU_File ) fclose(frU_File);
        if ( c_File ) fclose(c_File);
        return 1;
    }
    if ( c_File==NULL ) {
        printf("cannot load file : %s\n", argv[4]);
        if ( toU_File ) fclose(toU_File);
        if ( frU_File ) fclose(frU_File);
        if ( c_File ) fclose(c_File);
        return 1;
    }

    MapToC();

    if ( toU_File ) fclose(toU_File);
    if ( frU_File ) fclose(frU_File);
    if ( c_File ) fclose(c_File);
    return 0;
}

static void showhelp()
{
    printf("usage : \n");
    printf("    MapToC  charset-name  ToUnicodeMap   FromUnicodeMap   C-File");
}

static void trim(char * string)
{
    int length, i, j;
    const char * pb;
    if (string==NULL || string[0]==0)
        return;
    length = strlen(string);
    for ( i = length-1; i >= 0; i-- )
    {
        if ( string[i] == ' ' )
            string[i] = 0;
        else
            break;
    }
    if ( string[0] == 0 )
        return;
    i = 0;
    while ( string[i]==' ' )
        i++;
    if ( i == 0 )
        return;
    pb = & string[i];
    length = strlen(pb);
    for ( i = 0; i < length + 1; i++ )
        string[i] = pb[i];
    return;
}

unsigned char gethexvalue(unsigned char ch, unsigned int *perror)
{
    if ( ch >='0' && ch <= '9' )
    {
        *perror = 0;
        return ch - 0x30;
    }
    else if ( ch >='A' && ch <= 'F' )
    {
        *perror = 0;
        return ch - 'A' + 10;
    }
    else if ( ch >='a' && ch <= 'f' )
    {
        *perror = 0;
        return ch - 'a' + 10;
    }
    else
    {
        *perror = 1;
        return 0;
    }
}

static void HexStrToInt(unsigned char* str, unsigned int * pdwValue, unsigned int * perror)
{
    int i;
    unsigned char * pc;
    unsigned int v = 0;
    if ( str[0]=='0' && (str[1]=='X' || str[1]=='x'))
        pc = &str[2];
    else
        pc = str;
    i = 0;
    while (1)
    {
        unsigned int cv, error;
        if ( pc[i] == 0 )
            break;
        cv = gethexvalue(pc[i], &error);
        if ( error )
        {
            *perror = 1;
            return;
        }
        v <<= 4;
        v |= cv;
        i++;
    }
    *pdwValue = v;

    *perror = 0;
    return;
}

static void process_line(unsigned char *line, unsigned short* pwTab)
{
    unsigned char token1[256], token2[256];
    unsigned char * pt;
    unsigned index, value, error;
    int i;
    if ( line==NULL || line[0]==0 )
        return;
    for ( i = 0; ; i++ ) {
        if ( line[i]==0 )
            break;
        if ( line[i]=='\n' || line[i]=='\r' )
            line[i] = 0;
    }
    //////
    trim(line);
    if ( line[0]=='/' && line[1]=='/' )
        return;
    /////
    pt = strchr(line, '\t');
    if ( pt == NULL )
        return;
    strncpy(token1, line, pt - line);
    token1[pt - line] = 0;
    trim(token1);
    pt++;
    strncpy(token2, pt, sizeof(token2)-1);
    token2[sizeof(token2)-1] = 0;
    trim(token2);
    pt = strchr(token2, '/');
    if ( pt ) {
        if ( *pt == '/' && *(pt+1) == '/' )
            *pt = 0;
    }
    trim(token2);
    /////////
    HexStrToInt(token1, &index, &error);
    if ( error )
    {
        printf("Error : Line ");
        return;
    }
    HexStrToInt(token2, &value, &error);
    if ( error )
    {
        printf("Error : Line ");
        return;
    }

    if ( index <= 0xffff )
        pwTab[index] = (unsigned short) value;
    return;
}

static void LoadMap(unsigned short* pwTab, FILE * fp)
{
    int r;

    memset(linedata, 0, sizeof(linedata));
    fgets(linedata, sizeof(linedata), fp);
    while ( !feof(fp) )
    {
        process_line(linedata, pwTab);
        memset(linedata, 0, sizeof(linedata));
        fgets(linedata, sizeof(linedata), fp);
    }
}

static void LoadToUnicodeMap()
{
    memset(toTab, 0xff, sizeof(toTab));
    LoadMap(toTab, toU_File);
}

static void LoadFromUnicodeMap()
{
    memset(frTab, 0xff, sizeof(frTab));
    LoadMap(frTab, frU_File);
}

static void MapToC()
{
    LoadToUnicodeMap();
    LoadFromUnicodeMap();
    BuildAnsi2UniTable();
    BuildUni2AnsiTable();
}

static int TestAreaNull(const unsigned short *pArea)     //测试一个256个word的区域内是否全部为0xffff,全部为0则返回1,否则返回0
{
    unsigned i;
    int r;
    for ( i = 0; i < 256; i++ )
    {
        if ( pArea[i] != 0xffff )
            return 0;
    }
    return 1;
}

static void BuildTable(unsigned char flag, unsigned short* pwTab)   // flag==0, ANSI toUnicode, flag==1, Unicode To ANSI
{
    static unsigned char map[256];
    static unsigned short areadata[256];
    unsigned area;
    unsigned char area_counter;
    const unsigned short * tab;
    unsigned k;
    //--------------

    tab = pwTab;
    memset(map, 0xff, 256);
    area_counter = 0;
    if (flag==0)
        fprintf(c_File, "static const unsigned char %s_ToUniAreaTab[] = { \n" , pbCharsetName);
    else if (flag==1)
        fprintf(c_File, "static const unsigned char %s_FromUniAreaTab[] = { \n" , pbCharsetName);
    for ( area = 0; area < 256; area++ )
    {
        if ( ! TestAreaNull( & tab[ 256*area ] ))
        {
            map[area] = area_counter;
            area_counter++;
        }
    }
    for ( k = 0; k < 16; k++ )
        fprintf(c_File, "    0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X, //0x%02X \n",
            map[16*k+0x00],map[16*k+0x01],map[16*k+0x02],map[16*k+0x03],map[16*k+0x04],map[16*k+0x05],map[16*k+0x06],map[16*k+0x07],
            map[16*k+0x08],map[16*k+0x09],map[16*k+0x0a],map[16*k+0x0b],map[16*k+0x0c],map[16*k+0x0d],map[16*k+0x0e],map[16*k+0x0f],
            16*k  );
    fprintf(c_File, "};\n\n");
    //--------------
    if (flag==0)
        fprintf(c_File, "static const unsigned short %s_ToUniMapTab [] = { \n", pbCharsetName);
    else if (flag==1)
        fprintf(c_File, "static const unsigned short %s_FromUniMapTab [] = { \n", pbCharsetName);
    for ( area = 0; area < 256; area++ )
    {
        unsigned short ch;
        unsigned short i;
        if ( TestAreaNull( & tab[ 256*area ] ))
            continue;
        fprintf(c_File, "    //area = 0x%02X\n", area);
        memcpy(areadata, & tab[ 256*area ], 256*sizeof(short));
        for ( k = 0; k < 32; k++ )
        {
            fprintf(c_File, "    0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X, //0x%04X-0x%04X\n",
                    areadata[ 8*k + 0],areadata[ 8*k + 1],areadata[ 8*k + 2],areadata[ 8*k + 3],
                    areadata[ 8*k + 4],areadata[ 8*k + 5],areadata[ 8*k + 6],areadata[ 8*k + 7],
                    (area << 8) + 8*k , (area << 8) + 8*k + 7);
        }
    }
    fprintf(c_File, "};\n\n");
    return;
}

static void BuildAnsi2UniTable(void)
{
    BuildTable(0, toTab);
}

static void BuildUni2AnsiTable(void)
{
    BuildTable(1, frTab);
}








